package cn.itsource.ymcc.service.impl;


import cn.itsource.exception.GlobalException;
import cn.itsource.result.JSONResult;
import cn.itsource.util.AssertUtil;
import cn.itsource.util.StrUtils;
import cn.itsource.util.VerifyCodeUtils;
import cn.itsource.ymcc.config.SmsCodeProperties;
import cn.itsource.ymcc.constance.CommonExceptionEnum;
import cn.itsource.ymcc.constance.RedisConstant;
import cn.itsource.ymcc.domain.MessageSms;
import cn.itsource.ymcc.dto.RedisSMSCodeValueDTO;
import cn.itsource.ymcc.dto.SmsCodeDTO;
import cn.itsource.ymcc.service.IMessageSmsService;
import cn.itsource.ymcc.service.IVerifycodeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.concurrent.TimeUnit;


@Service
@Slf4j
public class VerifycodeServiceImpl implements IVerifycodeService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private SmsCodeProperties smsCodeProperties;

    @Autowired
    private IMessageSmsService iMessageSmsService;



    //@Value("${smscode.expire}")
    //private Long expire;
    //@Value("${smscode.interval}")
    //private Long interval;


    /*
       1.判断参数(手机号,图形验证码,key)


	   2.生成code(抽成一个方法)
	    是否已经存在redis中
	        2.1存在
	            判断时间戳
	            2.1.1如果在规定的时间内发的请求  那么需要抛异常
				2.1.2如果不在时间内  返回这个code
	        2.2不存在
	            2.2.1生成smsCode()

	   3.存放在redis中-->调用短信发送的工具类(自己写)



	   4.存db(t_message_sms)


	存db()
     */
    @Override
    public JSONResult sendSmsCode(SmsCodeDTO dto) {
        //1.判断参数(手机号,图形验证码,key)
        //1.1 图片验证码校验
        //如果校验失败  是不是应该抛异常'
        boolean checkImgCode = checkImgCode(dto.getImageCode(), dto.getImageCodeKey());
//        AssertUtil.isTrue(checkImgCode,
//                CommonExceptionEnum.IMG_CODE_ERROR.getMessage(),
//                CommonExceptionEnum.IMG_CODE_ERROR.getCode());
        AssertUtil.isTrue(checkImgCode,CommonExceptionEnum.IMG_CODE_ERROR.getMessage()+CommonExceptionEnum.IMG_CODE_ERROR.getCode());

        //生成存redis时候的value对象
        RedisSMSCodeValueDTO redisSMSCodeValueDTO = generateSmsCode(dto);
        String redisKey = RedisConstant.REDIS_SMS_CODE_PREFIX + dto.getMobile();
        redisTemplate.opsForValue().set(redisKey, redisSMSCodeValueDTO, smsCodeProperties.getExpire(), TimeUnit.MINUTES);
        //发送消息
        String message = sendSMSCode(redisSMSCodeValueDTO.getCode(),dto.getMobile());
        insertSMSSendLog(dto, message);
        return JSONResult.success();
    }

    @Override
    public JSONResult getImageCode(String imageCodeKey) {
        // 1.判断参数是否为空
        if (org.springframework.util.StringUtils.isEmpty(imageCodeKey)){
            throw new GlobalException("参数不能为空，请传递正确参数！");
        }
        // 2.获取到随机4位字符串
        String imageCode = StrUtils.getComplexRandomString(4);
        // 3.使用工具类生成Base64图形验证码字符串
        String imageBase64Str = VerifyCodeUtils.verifyCode(100,30,imageCode);
        // 4.根据key、value保存到Redis中，并设置三分钟有效
        redisTemplate.opsForValue().set(imageCodeKey, imageCode, 3, TimeUnit.MINUTES);
        return JSONResult.success(imageBase64Str);
    }

    /**
     * 短信发送日志存入DB
     *
     * code   title
     * code---->title
     */
    private void insertSMSSendLog(SmsCodeDTO dto,String message){
        //创建消息实体类
        MessageSms messageSms = new MessageSms();
        messageSms.setTitle("用户注册短信验证码");
        messageSms.setContent(message);



        //获取ip地址 start
        ServletRequestAttributes servletRequestAttributes =  (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest httpServletRequest = servletRequestAttributes.getRequest();
        messageSms.setIp( httpServletRequest.getRemoteAddr());
        //获取ip地址 end


        messageSms.setSendTime(new Date());
        iMessageSmsService.insert(messageSms);
        log.info("=======================================");
        log.info(messageSms.getId().toString());
    }


    /**
     * 图片验证码校验
     */
    private boolean checkImgCode(String imgCode, String imgKey) {


        //假装   你图形验证码  如果写的是111111
//        //我就认为是错的
//        if (StringUtils.equals("111111", imgCode)) {
//            return false;
//        }
//        return true;


        if (org.springframework.util.StringUtils.isEmpty(imgCode) || StringUtils.isEmpty(imgKey)){
            throw new GlobalException("参数不能为空！");
        }

        //2.判断图形验证码是否正确以及存在
        Object imageCodeValueTmp = redisTemplate.opsForValue().get(imgKey);
        if (imageCodeValueTmp == null){
            throw new GlobalException("验证码已过期，请重新获取！");
        }
        // 忽略大小写比较图形验证码是否正确
        if (!imageCodeValueTmp.toString().equalsIgnoreCase(imgCode)){
            throw new GlobalException("验证码错误，请重新输入！");
        }
        return true;
    }


    /*
    生成手机验证码

    是否已经存在redis中
	        2.1存在
	            判断时间戳
	            2.1.1如果在规定的时间内发的请求  那么需要抛异常
				2.1.2如果不在时间内  返回这个code
	        2.2不存在
	            2.2.1生成smsCode()
     */
    private RedisSMSCodeValueDTO generateSmsCode(SmsCodeDTO dto) {
        //现在只有一个手机号
        //redis 生成的规则:
        //REDIS_SMS_CODE:13838389438
        String redisKey = RedisConstant.REDIS_SMS_CODE_PREFIX + dto.getMobile();
        RedisSMSCodeValueDTO redisSMSCodeValueDTO =(RedisSMSCodeValueDTO)redisTemplate.opsForValue().get(redisKey);


        //如果不存在
        if (redisSMSCodeValueDTO==null) {
            redisSMSCodeValueDTO = new RedisSMSCodeValueDTO(StrUtils.getComplexRandomString(6), new Date());
            return redisSMSCodeValueDTO;
        }
        //---------------------
        Date createDate = redisSMSCodeValueDTO.getCreateDate();

        //规定  间隔时间是1分钟
        if ((System.currentTimeMillis()-createDate.getTime())/1000< smsCodeProperties.getInterval()) {
            throw new GlobalException("手速太快了  晚点再来");
        }else{
            return redisSMSCodeValueDTO;
        }
        //------------------------

    }


    private String sendSMSCode(String code,String mobie){
        //TODO 调用发送消息的工具
        log.info("手机号是("+mobie+")拿去你的验证码" + code);
        return "手机号是("+mobie+")拿去你的验证码" + code;
    }
}
